package com.liuke.question4;

import com.google.common.collect.Lists;
import com.liuke.question4.handler.CatPipeHandler;
import com.liuke.question4.handler.GrepPipeHandler;
import com.liuke.question4.handler.StdoutPipeHandler;
import com.liuke.question4.handler.WcPipeHandler;
import com.liuke.question4.utils.FileUtil;

import javax.naming.directory.InvalidSearchFilterException;
import java.io.IOException;
import java.io.PipedInputStream;
import java.io.PipedOutputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;

/**
 * @Auther: 刘科
 * @Date: 2021/07/04/9:07
 * @Description:
 */
public class Controller {
    //输入流
    private static final Scanner scanner = new Scanner(System.in);

    /**
     * 黑框命令处理
     */
    public static boolean handleCommand() throws IOException {
        System.out.print("JavaShell " + FileUtil.getCurrentPath() + "$ ");
        String line = scanner.nextLine().trim();

        if (line.length() == 0) return true;
        if (line.equals("exit")) return false;


        handleCommandExecute(line);
        return true;
    }

    private static void handleCommandExecute(String line) throws IOException {
        PipedOutputStream head = new PipedOutputStream();
        PipedInputStream tail = new PipedInputStream();

        String[] groups = line.split("\\|");
        //初始化输入流列表和输出流列表
        PipedInputStream[] inputArray = getInputList(groups.length);
        PipedOutputStream[] outputArray = getOutputList(groups.length);
        outputArray[0] = head;
        inputArray[inputArray.length - 1] = tail;

        for (int i = 0; i < groups.length; i++) {
            String item = groups[i];
            item = item.trim();

            String[] args = item.split(" ");
            String command = args[0];
            if (!CommandEnum.contains(command)) {
                throw new RuntimeException(command);
            }
            List<String> files = getFiles(args, command);

            PipedInputStream curInStream = inputArray[i];
            PipedOutputStream curOutStream = outputArray[i + 1];

            curOutStream.connect(inputArray[i + 1]);

            if (files.size() != 0) {
                for (String filename : files) {
                    String errMsg = FileUtil.checkFile(command, filename);
                    if (errMsg != null) {
                        throw new RuntimeException(errMsg);
                    }
                }

                curInStream = new PipedInputStream();

                inputArray[i] = curInStream;

                PipedOutputStream fileStream = new PipedOutputStream();
                fileStream.connect(curInStream);
                new ReadFileThread(fileStream, files).start();
            }
            Runnable runnable = getCommandRunnable(command, args, curInStream, curOutStream);
            new Thread(runnable).start();
        }

        //所有命令执行完后，输入流到了tail，默认运行tail的StdoutPipeHandler就可以输出到控制台
        Thread stdoutThread = new Thread(new StdoutPipeHandler(tail));
        stdoutThread.start();

        try {
            //优先执行stdoutThread线程，主线程等待。
            stdoutThread.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    private static Runnable getCommandRunnable(String command, String[] args, PipedInputStream in, PipedOutputStream out) {
        if (command.equals(CommandEnum.CAT.value)) {
            return new CatPipeHandler(in, out);
        } else if (command.equals(CommandEnum.WC.value)) {
            return new WcPipeHandler(in, out);
        } else if (command.equals(CommandEnum.GREP.value)) {
            String keyword = args[1];
            return new GrepPipeHandler(in, out, keyword);
        }
        return null;
    }

    private static List<String> getFiles(String[] args, String command) {
        //因为grep有一个关键字的参数，所以需要区别是否是grep命令
        int start = 1;
        if (command.equals(CommandEnum.GREP.value)) {
            start = 2;
        }
        List<String> result = new ArrayList<>();
        if (args.length > 1) {
            for (int i = start; i < args.length; i++) {
                result.add(args[i].trim());
            }
        }
        return result;
    }

    private static PipedInputStream[] getInputList(int groupLength) {
        PipedInputStream[] result = new PipedInputStream[groupLength + 1];
        for (int i = 0; i < groupLength; i++) {
            result[i] = new PipedInputStream();
        }
        return result;
    }
    private static PipedOutputStream[] getOutputList(int groupLength) {
        PipedOutputStream[] result = new PipedOutputStream[groupLength + 1];
        for (int i = 1; i < groupLength + 1; i++) {
            result[i] = new PipedOutputStream();
        }
        return result;
    }
}
